package omq.filetransfer;

import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;

import omq.exception.OMQPropertiesReaderException;
import omq.exception.OMQException;
import omq.api.logger.*;
import omq.utils.*;


import java.util.Timer;
import java.util.TimerTask;

import javax.xml.rpc.ServiceException;

import com.sun.org.apache.bcel.internal.classfile.SourceFile;

/*
 * OMQ FileTransfer:
 * -----------------
 * 
 * OMQ FileTransfer system is a fully operational file system transfer protocol over OMQ.
 * It sends files to messages in OMQ queue and later receives them back to files.
 *  
 * All system parameters (including OMQ parameters and file-system parameters) are configured using these 2 properties file: 
 * 		for file sender   - omqsend.properties
 * 		for file receiver - omqreceive.properties
 * 
 * Following are the runnable options:
 *    
 * OMQSendFile - sends one specific file specified in parameter omq.ft.filename to a queue.
 * OMQSendFiles - a deamon that wait for new files on the folder omq.ft.path and sends all the files from this folder.
 * OMQReceiveFile - receives only one file from queue into the folder omq.ft.path. 
 * OMQReceiveFiles - a deamon that samples the queue every interval and saves the messages as files. 
 * there are 2 properties file to configure.
 *  
 *  Author  	  	: Hagai Izenberg
 *  Creating Date 	: 20-05-2008
 *  Company 		: OMQI
 */

public class OMQSendFiles  {

	/**
	 * @param args
	 * @throws ClassNotFoundException 
	 * @throws IOException 
	 * @throws OMQException 
	 */
	
	String sendingDirectoryStr;
	String proccessingDirectoryStr = "processing";
	String finishedDirectoryStr = "finished";

	File sendingDirectory;
	File proccessingDirectory;
	File finishedDirectory;
	
	boolean success=true;
	OMQPropertiesReader prop;
	OMQFileTransfer sender;

	public static void main(String[] args)
	{		
		final String defaultPropertiesFile = "omqsend.properties";
		String propertiesFile = defaultPropertiesFile;
		
		OMQLogger.getInstance().info("#################################################################################");
		OMQLogger.getInstance().info("# OMQ File Transfer version "+OMQFileTransfer.getVersion()+" - send files started at "+(FileUtil.time("yyyy.MM.dd 'at' hh:mm:ss")));
		OMQLogger.getInstance().info("#################################################################################");

		if (args.length>0)
		{
			if (args[0].compareToIgnoreCase("-classpath")!= 0)
			{
				propertiesFile = args[0];
				OMQLogger.getInstance().info("using given properties file named "+propertiesFile);
			}
		}
		else
		{
			OMQLogger.getInstance().info("Using default properties file named "+propertiesFile+", you can pass a properties file name as a parameter to this java program");
		}
		
		OMQSendFiles send = new OMQSendFiles();
		send.sendFiles(propertiesFile);
	}
	
	public void sendFiles(String propertiesFile)
	{
		try 
		{	
			// ------------------------------------------------------------
			// getting properties
			// ------------------------------------------------------------
			prop = OMQPropertiesReader.createOMQPropertiesReader(propertiesFile);
			sender = new OMQFileTransfer(prop);

			String ftSleepTime = prop.getProperty("omq.ft.sleeptime");
			OMQLogger.getInstance().info("omq.ft.sleeptime in properties file is set to "+ftSleepTime);
			int iSleepTime = (new Integer(ftSleepTime)).intValue();
			OMQLogger.getInstance().info("sleep time is set to "+iSleepTime+" seconds");

			// ------------------------------------------------------------
			// verifying and checking objects for the 3 directories we use
			// ------------------------------------------------------------
			sendingDirectoryStr = FileUtil.addSlashInFilename(sender.getFtPath());
			
			proccessingDirectoryStr = FileUtil.addSlashInFilename(sendingDirectoryStr+proccessingDirectoryStr);
			FileUtil.createDirectoryIfDoesntExist(proccessingDirectoryStr);
			finishedDirectoryStr = FileUtil.addSlashInFilename(sendingDirectoryStr+finishedDirectoryStr);
			FileUtil.createDirectoryIfDoesntExist(finishedDirectoryStr);
			
			sender.setFtPath(proccessingDirectoryStr);
			
			sendingDirectory = new File(sendingDirectoryStr);
			proccessingDirectory = new File(proccessingDirectoryStr);
			finishedDirectory= new File(finishedDirectoryStr);
			
			// ------------------------------------------------------------
			// looping on sending the files
			// ------------------------------------------------------------
			while (true)
			{
				// ------------------------------------------------------------
				// we loop while there are still files to process
				// ------------------------------------------------------------
				while (proccessFiles())
				{
					OMQLogger.getInstance().info("checking if there are more file to send before going to sleep");
				}

				// ------------------------------------------------------------
				// when there are no more files to process - we sleep
				// ------------------------------------------------------------
				OMQLogger.getInstance().info("omq file transfer sender about to sleep "+iSleepTime+" seconds");
				synchronized (sender)
				{
					sender.pause(iSleepTime);
				}
				OMQLogger.getInstance().info("----------------------------------------------------------------");
				OMQLogger.getInstance().info("omq file transfer sender after sleeping "+iSleepTime+" seconds");
				//
			}
		}
		catch (OMQFileTransferInitException e) 
		{
			// TODO Auto-generated catch block
			OMQLogger.getInstance().error("failed to init OMQ file transfer enviroment",e);
			
			success = false;
		}
	
		catch (OMQPropertiesReaderException e) 
		{
			// TODO Auto-generated catch block
			OMQLogger.getInstance().error("failed to read properties file",e);
			
			success = false;
		}
		catch (InterruptedException e) 
		{
			// TODO Auto-generated catch block
			OMQLogger.getInstance().error("OMQ File send listener was interrupted, see attached excpetion for more info",e);
			
			success = false;
		}
		catch(java.lang.NumberFormatException e)
		{
			OMQLogger.getInstance().error("property omq.ft.sleeptime is not set to a number");
			
			success = false;			
		}
		catch (ServiceException e) 
		{
			// TODO Auto-generated catch block
			OMQLogger.getInstance().error("failed due to ServiceException",e);
			
			success = false;
		}

		if (success)
			OMQLogger.getInstance().info("OMQ File Transfer - send file - ended succesfully");
		else
			OMQLogger.getInstance().info("OMQ File Transfer - send file - ended with errors");

	}

	
	// ------------------------------------------------------------
	// this method is used to process the files
	// it returns the number of files sent
	// ------------------------------------------------------------
	private boolean proccessFiles() throws OMQFileTransferInitException
	{
		boolean moreFiles = false;
		// ------------------------------------------------------------
		// first we send files if some are left in the processing folder
		// ------------------------------------------------------------	
		OMQLogger.getInstance().info("trying to send files first (so old files are handled before new files arrives)");
		try
		{
			sendFiles();
			// ------------------------------------------------------------
			// then we try to get more files from the original folder and send them
			// ------------------------------------------------------------
			OMQLogger.getInstance().info("checking to see if there are files to send in "+sendingDirectoryStr);
			moreFiles = moveFilesToProccessedDirectory();
			if (moreFiles)
			{
				OMQLogger.getInstance().info("sending new files");
				sendFiles();
			}
		}
		catch (OMQFileTransferException e) 
		{
			// TODO Auto-generated catch block
			OMQLogger.getInstance().error("failed to send file",e);
			
			success = false;
		}	
		return moreFiles;
	}


	// ------------------------------------------------------------
	// this method send files from the processing folder and 
	// moves them to the finished folder
	// ------------------------------------------------------------
	private void sendFiles() throws OMQFileTransferException, OMQFileTransferInitException
	{
		File[] fileList = FileUtil.listFilesInFolder(proccessingDirectory);
		OMQLogger.getInstance().info("there are "+fileList.length+ " files to send in "+proccessingDirectory.getPath());

		// ------------------------------------------------------------
		// processing all files in processing folder
		// ------------------------------------------------------------
		for (int i=0; i<fileList.length; i++)
		{
			OMQLogger.getInstance().info("--------------------------------------------------");
			File currFile = fileList[i];
			OMQLogger.getInstance().info("about to send "+currFile.getName());

			// ------------------------------------------------------------
			// TODO send 1 file
			// ------------------------------------------------------------
			if (sender.sendFile(currFile.getName()))
			// ------------------------------------------------------------
			// TODO move 1 file to finished directory
			// ------------------------------------------------------------
			{
				String finishedFileName = "QMGR-"+sender.getOmqQueueManager()+"_Q-"+sender.getOmqQueue()+"_MsgID-"+sender.getLastMsgID()+"_TimeSent-"+FileUtil.time("yyyy-MM-dd_HHmmss")+"__FileName-"+currFile.getName();
				
				//FileUtil.moveFile(currFile, new File(finishedDirectoryStr+"msgid"+sender.getLastMsgID()+"_"+FileUtil.time("yyyy-MM-dd_HHmmss_")+currFile.getName()));
				FileUtil.moveFile(currFile, new File(finishedDirectoryStr+finishedFileName));
			}
			else
			{
				OMQLogger.getInstance().info("file "+currFile.getName()+" was not send and is still in processing directory");
			}
		}
	}
	private boolean moveFilesToProccessedDirectory()
	{
		int numOfFiles = FileUtil.moveFiles(sendingDirectory, proccessingDirectory);
		if (numOfFiles > 0)
			return true;
		else
			return false;
		
	}
}
